// Author: David Qin
// E-mail: david@hereapp.cn
// Date: 2014-11-05

(function ($) {
	
	// a case insensitive jQuery :contains selector
	$.expr[":"].searchableSelectContains = $.expr.createPseudo(function (arg) {
		return function (elem) {
			if (arg) return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
			else $(".searchable-select-items>div").removeClass("searchable-select-hide");
		};
	});
	
	$.searchableSelect = function (element, options) {
		this.element = element;
		this.options = options || {};
		this.init();
		
		var _this = this;
		
		this.searchableElement.click(function (event) {
			// event.stopPropagation();
			_this.show();
		}).on('keydown', function (event) {
			if (event.which === 13 || event.which === 40 || event.which == 38) {
				event.preventDefault();
				_this.show();
			}
		});
		
		$(document).on('click', null, function (event) {
			if (_this.searchableElement.has($(event.target)).length === 0)
				_this.hide();
		});
		
		this.input.on('keydown', function (event) {
			event.stopPropagation();
			if (event.which === 13) {         //enter
				event.preventDefault();
				_this.selectCurrentHoverItem();
				//回车回调
				if (_this.options.enterCallback) _this.options.enterCallback(_this.input);
				_this.hide();
			} else if (event.which == 27) { //ese
				_this.hide();
			} else if (event.which == 40) { //down
				_this.hoverNextItem();
			} else if (event.which == 38) { //up
				_this.hoverPreviousItem();
			}
		}).on('keyup', function (event) {
			
			if (event.which != 13 && event.which != 27 && event.which != 38 && event.which != 40)
				_this.filter();
			//监听搜索输入框回调
			if (_this.options.inputKeyUpCallback) _this.options.inputKeyUpCallback($(this));
		})
	}
	
	var $sS = $.searchableSelect;
	
	$sS.fn = $sS.prototype = {
		version: '0.0.1'
	};
	
	$sS.fn.extend = $sS.extend = $.extend;
	
	$sS.fn.extend({
		init: function () {
			
			var _this = this;
			this.element.hide();
			this.searchableElement = $('<div tabindex="0" class="searchable-select"></div>');
			// this.holder = $('<div class="searchable-select-holder"></div>');//旧的
			this.holder = $('<input type="text" readonly  class="searchable-select-holder" placeholder="' + (_this.options.placeholder ? _this.options.placeholder : "") + '" />');
			this.dropdown = $('<div class="searchable-select-dropdown searchable-select-hide"></div>');
			this.input = $('<input type="text" class="searchable-select-input" />');
			this.items = $('<div class="searchable-select-items"></div>');
			this.caret = $('<i class="layui-edge searchable-select-caret"></i>');
			
			this.scrollPart = $('<div class="searchable-scroll"></div>');
			this.hasPrivious = $('<div class="searchable-has-privious">...</div>');
			this.hasNext = $('<div class="searchable-has-next">...</div>');
			
			this.hasNext.on('mouseenter', function () {
				_this.hasNextTimer = null;
				
				var f = function () {
					var scrollTop = _this.items.scrollTop();
					_this.items.scrollTop(scrollTop + 20);
					_this.hasNextTimer = setTimeout(f, 50);
				}
				
				f();
			}).on('mouseleave', function (event) {
				clearTimeout(_this.hasNextTimer);
			});
			
			this.hasPrivious.on('mouseenter', function () {
				_this.hasPriviousTimer = null;
				
				var f = function () {
					var scrollTop = _this.items.scrollTop();
					_this.items.scrollTop(scrollTop - 20);
					_this.hasPriviousTimer = setTimeout(f, 50);
				}
				
				f();
			}).on('mouseleave', function (event) {
				clearTimeout(_this.hasPriviousTimer);
			});
			
			this.dropdown.append(this.input);
			this.dropdown.append(this.scrollPart);
			
			this.scrollPart.append(this.hasPrivious);
			this.scrollPart.append(this.items);
			this.scrollPart.append(this.hasNext);
			
			this.searchableElement.append(this.caret);
			this.searchableElement.append(this.holder);
			this.searchableElement.append(this.dropdown);
			this.element.after(this.searchableElement);
			
			this.buildItems();
			this.setPriviousAndNextVisibility();
		},
		
		filter: function () {
			var text = this.input.val();
			this.items.find('.searchable-select-item').addClass('searchable-select-hide');
			this.items.find('.searchable-select-item:searchableSelectContains(' + text + ')').removeClass('searchable-select-hide');
			if (this.currentSelectedItem && this.currentSelectedItem.hasClass('searchable-select-hide') && this.items.find('.searchable-select-item:not(.searchable-select-hide)').length > 0) {
				this.hoverFirstNotHideItem();
			}
			
			this.setPriviousAndNextVisibility();
		},
		
		hoverFirstNotHideItem: function () {
			this.hoverItem(this.items.find('.searchable-select-item:not(.searchable-select-hide)').first());
		},
		
		selectCurrentHoverItem: function () {
			if (this.currentHoverItem && !this.currentHoverItem.hasClass('searchable-select-hide'))
				this.selectItem(this.currentHoverItem);
		},
		
		hoverPreviousItem: function () {
			if (!this.hasCurrentHoverItem())
				this.hoverFirstNotHideItem();
			else {
				var prevItem = this.currentHoverItem.prevAll('.searchable-select-item:not(.searchable-select-hide):first')
				if (prevItem.length > 0)
					this.hoverItem(prevItem);
			}
		},
		
		hoverNextItem: function () {
			if (!this.hasCurrentHoverItem())
				this.hoverFirstNotHideItem();
			else {
				var nextItem = this.currentHoverItem.nextAll('.searchable-select-item:not(.searchable-select-hide):first')
				if (nextItem.length > 0)
					this.hoverItem(nextItem);
			}
		},
		
		buildItems: function () {
			var _this = this;
			this.element.find('option').each(function () {
				if ($(this).text().length == 0) return;
				var item = $('<div class="searchable-select-item" data-value="' + $(this).attr('value') + '">' + $(this).text() + '</div>');
				if (this.selected) {
					_this.selectItem(item);
					_this.hoverItem(item);
				}
				
				item.on('mouseenter', function () {
					$(this).addClass('hover');
				}).on('mouseleave', function () {
					$(this).removeClass('hover');
				}).click(function (event) {
					event.stopPropagation();
					_this.selectItem($(this));
					_this.hide();
					
					//选择option后执行回调
					if (_this.options.optionCallback) {
						var value = $(this).attr("data-value");
						var text = $(this).text();
						_this.options.optionCallback(value, text);
					}
				});
				
				_this.items.append(item);
			});
			
			this.items.on('scroll', function () {
				_this.setPriviousAndNextVisibility();
			})
		},
		show: function () {
			this.dropdown.removeClass('searchable-select-hide');
			this.input.focus();
			this.status = 'show';
			this.caret.addClass("selected");//下三角
			this.setPriviousAndNextVisibility();
			
		},
		
		hide: function () {
			if (!(this.status === 'show'))
				return;
			
			if (this.items.find(':not(.searchable-select-hide)').length === 0)
				this.input.val('');
			this.dropdown.addClass('searchable-select-hide');
			this.searchableElement.trigger('focus');
			this.status = 'hide';
			this.caret.removeClass("selected");//下三角
		},
		
		hasCurrentSelectedItem: function () {
			return this.currentSelectedItem && this.currentSelectedItem.length > 0;
		},
		
		selectItem: function (item) {
			if (this.hasCurrentSelectedItem())
				this.currentSelectedItem.removeClass('selected');
			
			this.currentSelectedItem = item;
			item.addClass('selected');
			
			this.hoverItem(item);
			this.holder.val(item.text());
			
			var value = item.data('value');
			this.holder.data('value', value);
			this.element.val(value);
			
			if (this.options.afterSelectItem) {
				this.options.afterSelectItem.apply(this);
			}
		},
		
		hasCurrentHoverItem: function () {
			return this.currentHoverItem && this.currentHoverItem.length > 0;
		},
		
		hoverItem: function (item) {
			if (this.hasCurrentHoverItem())
				this.currentHoverItem.removeClass('hover');
			
			if (item.outerHeight() + item.position().top > this.items.height())
				this.items.scrollTop(this.items.scrollTop() + item.outerHeight() + item.position().top - this.items.height());
			else if (item.position().top < 0)
				this.items.scrollTop(this.items.scrollTop() + item.position().top);
			
			this.currentHoverItem = item;
			item.addClass('hover');
		},
		
		setPriviousAndNextVisibility: function () {
			if (this.items.scrollTop() === 0) {
				this.hasPrivious.addClass('searchable-select-hide');
				this.scrollPart.removeClass('has-privious');
			} else {
				this.hasPrivious.removeClass('searchable-select-hide');
				this.scrollPart.addClass('has-privious');
			}
			
			if (this.items.scrollTop() + this.items.innerHeight() >= this.items[0].scrollHeight) {
				this.hasNext.addClass('searchable-select-hide');
				this.scrollPart.removeClass('has-next');
			} else {
				this.hasNext.removeClass('searchable-select-hide');
				this.scrollPart.addClass('has-next');
			}
		}
	});
	
	$.fn.searchableSelect = function (options) {
		var sS;
		this.each(function () {
			sS = new $sS($(this), options);
		});
		return sS;//返回当前对象，那边接收到后可以进行后期的修改对象操作
		//return this;//以前的
	};
	
})(jQuery);